<?php
/**
 * Created by .
 * User: luogan
 * Date: 2021/12/21
 */

declare(strict_types=1);

namespace App\Validate\Api;


use App\Exception\ValidationException;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;

abstract class BaseValidate
{
    /**
     * @Inject()
     * @var ValidatorFactoryInterface
     */
    protected $validationFactory;

    protected $rule = [];
    protected $message = [];
    protected $parameters = [];

    /**
     * 规则
     * @return array
     */
    protected abstract function rule(): array;

    /**
     * 自定义，提示语
     * @return array
     */
    protected abstract function message(): array;

    /**
     * 自定义方法，以匿名方式命名
     * @return array
     */
    protected abstract function callBack(): array;

    public function __construct()
    {
        $rules = $this->rule();
        foreach ($rules as $key => $rule) {
            if (is_string($rule)) {
                $rules[$key] = explode("|", $rule);
            }
        }
        $this->rule = $rules;
        $this->message = $this->message();
    }

    protected function only(array $ruleArr): self
    {
        $ruleArr = array_flip($ruleArr);
        $this->rule = array_intersect_key($this->rule, $ruleArr);
        return $this;
    }

    /**
     * @param $field
     * @param $rule
     */
    protected function append(string $field, $rule): self
    {
        $rule = is_array($rule) ? $rule : explode("|", $rule);
        if (isset($this->rule[$field])) {
            $this->rule[$field] = array_unique(array_merge($this->rule[$field], $rule));
        }
        return $this;
    }

    protected function remove(string $field, $rule): self
    {
        $rule = is_array($rule) ? $rule : explode("|", $rule);
        if (isset($this->rule[$field])) {
            $this->rule[$field] = array_diff($this->rule[$field], $rule);
        }
        return $this;
    }

    final public function scene(string $scene): self
    {
        $scene = 'scene_' . $scene;
        $sceneName = preg_replace_callback('/_+([a-z])/', function ($matches) {
            return strtoupper($matches[1]);
        }, $scene);

        if (method_exists($this, $sceneName)) {
            return call_user_func([$this, $sceneName]);
        }
        return $this;
    }


    final public function validate(array $data)
    {

        $callBackList = $this->callBack();
        $validationFactory = $this->validationFactory;
        foreach ($callBackList as $funcName => $callBack) {
            $validationFactory->extend($funcName, $callBack);
        }
        $this->parameters = $data;

        $validator = $validationFactory->make($data, $this->rule, $this->message);
        if ($validator->fails()) {
            $error = $validator->errors();
            $msg = '';
            foreach ($error->all() as $message) {
                $msg .= $message.';';
            }
            throw new ValidationException($msg);
        }
    }
}
